home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / CIS_GAME.ARJ / QVOXL2.THD < prev    next >
Text File  |  1993-06-25  |  43KB  |  896 lines

  1. ______________________________ Subj: Oct Trees ______________________________
  2.  
  3. Fm: Mark Betz/Ass't SysOp 76605,2346
  4. To: Dan Corritore 70243,1110 (X)
  5.  
  6. >> I remember that discussion, although I don't recall
  7.    anything about using trees in it, but then again,
  8.  
  9. [ Editor's note: see VOXEL.THD, GAMERS section 11 ]
  10.  
  11. That subject, which Chris Lampton, at least, knows a lot more about then I,
  12. involves using an Octree (a tree where each node has eight links). I believe
  13. it's done this way (Chris, jump in and tell me far off I am <g>):
  14.  
  15. You consider your world space as a cube (or in your case a 2D rectangle)
  16. which is subdivided into eight interior cubes, each of which has a link
  17. pointer in the parent cube (in the case of the children of the root node,
  18. their parent is the world space. Within each node, a child pointer is null
  19. (the cube of space is undefined) if there is nothing in it, or has a pointer
  20. to a node if there is. That node is then subdivided according to the same
  21. rule. Each of the cubes is known as a Voxel. The advantage is that you do not
  22. store positional data for cubes (or rectangles) of empty space. As I remember
  23. this is most applicable to flight simulators, where huge portions of the
  24. world database contain nothing at all. In your case I could see using a
  25. quadtree (as above, with a four-level subdivision of a 2D rectangle). Each
  26. node would contain the rectangle extents, and a linked list of objects
  27. present in that rectangle. 
  28.                                                 --Mark
  29. ...........................................................................
  30.  
  31. Fm: Dan Corritore 70243,1110
  32. To: Mark Betz/Ass't SysOp 76605,2346 (X)
  33.  
  34. What you said sounds almost exactly like what Kevin Gliner suggested. In
  35. fact, it sounds a whole lot like tiles, although a tile wouldn't have a
  36. linked list, and it wouldn't be on a tree. Which is one thing I can't
  37. understand with what you said.. why not just have an array (the size of the
  38. smallest subdivision you have*(size of the world/subdivision) or something as
  39. such), with linked list pointers coming off of them? That way, you wouldn't
  40. have to traverse the tree to get to a certain section, only to traverse a
  41. linked list afterwards.         What I'm using for my tree stuff isn't like
  42. that.. well, actually, I do have a few subdivisions of the world (if it's
  43. 32000*32000 pixels, the first node would be at 16000*16000, etc.. until a
  44. suitable enough division is reached.. of course, I could just use an array of
  45. tree's starting at those divisions), but I put the objects into their correct
  46. places(not on linked lists--each object has child pointers which are
  47. traversed based on compares).         I hope you understood that..(and I hope
  48. I understood you correctly<g>) 
  49.    Thanks,
  50.         _Dan 
  51. ...........................................................................
  52.  
  53. Fm: Mark Betz/Ass't SysOp 76605,2346
  54. To: Dan Corritore 70243,1110
  55.  
  56. Well, the biggest reason is that, with an array, you'd have to check every
  57. element to see if the linked list was empty or not. With the Octree, if the
  58. space defined by the child pointer is empty, then the pointer is null.
  59.  
  60.                                                         --Mark
  61. ...........................................................................
  62.  
  63. Fm: Hans Peter Rushworth 100031,473
  64. To: Dan Corritore/MOTM 70243,1110
  65.  
  66. An array would be preferred if you were interested in all points in the 3D
  67. space, even parts that are not visible. In most cases you are interested only
  68. where a surface lies in the the 3D space.
  69.  
  70. You could store such a surface in a pair of 2D arrays where one array is used
  71. to indicate the altitude of a point in the surface, and the other array is
  72. used to store say a colour value for that point. The first problem with this
  73. if you have a vertical feature like a cliff, you store less surface detail
  74. than where the surface is a plain (which is usually less "interesting"). The
  75. second problem is that even if there are large areas of no interest, the
  76. storage still needs to be allocated for that area.
  77.  
  78. With a voxel approach, memory is only used where detail is present, and where
  79. the surface exists. Since the voxel structure is fractal, you can add extra
  80. detail to cater for special situations that have a lot of detail, and the
  81. problem of "cliffs" is much less of a problem.
  82.  
  83. For very large 3D spaces, octree (voxel) storage schemes are much more
  84. efficient than arrays, and they have the added benefit of "adaptive"
  85. resolution control, wherein you restrict the depth of your search for more
  86. distant objects.
  87.  
  88. In practice you might use a hybrid approach, say have an octree of arrays.
  89. The arrays are there to provide detail that is easier to process (as you say)
  90. You might call this array a voxary <g>
  91.  
  92. Peter.
  93. ...........................................................................
  94.  
  95. Fm: Hans Peter Rushworth 100031,473
  96. To: John W. Ratcliff 70253,3237 (X)
  97.  
  98. No John, I have no connection with the commanche people. I'm led to believe
  99. they did not use the voxel surface representation (as I described it) because
  100. in CMO the areas with large change in altitude give rise to "tall rectangles"
  101. which is the result you would get when using two 2D arrays for colour and
  102. altittude. (Unless I remember incorrectly).
  103.  
  104. Of course it's still possible they used a quadtree in place of either of the
  105. 2D arrays, but this would not be computationally efficient IMO.
  106.  
  107. I have looked at CONTOUR.ZIP and I would agree that CMO probably uses a
  108. similar minmax method to mask displayed pixels in the vertical, but there is
  109. still the problem of ordering the surface altitudes, and I'm not sure what
  110. method you used for that, or whether CMO uses a similar or novel approach.
  111.  
  112. I have implemented a high speed display system using a different sort of tree
  113. (a Binary Space Partitioning Tree), which was mainly used for hidden surface
  114. removal of polygon data. The BSP tree when appropriately traversed visits
  115. nodes in order of distance, irrespective of the view position. The BSP system
  116. IMO is a very efficient for static, non-intersecting databases.
  117.  
  118. As for CMO, I suspect they simply calculate the vanishing points of the
  119. horizon where it meets the screen edges (which it is contrived to do always),
  120. and together with the mappings of the bottom edge screen co-ordinates, find a
  121. 4-point mapping into their altitude and colour arrays. It is then a simple
  122. matter to use incremental interpolation to sample a vertical "slice"
  123. representing colour and altitudes for each display pixel, and then paint them
  124. using the minmax hidden surface method. I have used a similar sampling scheme
  125. to map flat texture maps into arbitrarily oriented 3D polygons, and using
  126. incremental sampling, the speed can be very fast, even in C. 
  127.  
  128. The sampling scheme automatically deals with the replication and skipping of
  129. map pixels (if the map is visually very close, the same point is sampled more
  130. than once, if distant, pixels are "missed out"). Rotations are dealt with by
  131. transforming only the initial 4 screen corner points. All interpolated
  132. samples that are taken using these points are implicitly rotated.
  133.  
  134. I could probably knock up a program to demonstrate this using a fractal
  135. plasma surface if you are interested, but you might have to wait a week or
  136. two. 
  137.  
  138. Peter.
  139. ...........................................................................
  140.  
  141. Fm: Mark Betz/Ass't SysOp 76605,2346
  142. To: Hans Peter Rushworth 100031,473 (X)
  143.  
  144. >> voxarray
  145.  
  146. I love it! Patent that fast <g>.
  147.  
  148. I'm no expert on Octrees, but I think I have the basic concept down. What I'm
  149. wondering is what information you consider it necessary to store in each node
  150. of the tree. I'm thinking that, since the node represents a cube, you have to
  151. define the cube's extent. You then have to have a way to travel to the
  152. structures defining the objects in the space. This might be a pointer to a
  153. linked list of objects.
  154.  
  155. The most puzzling question (at this moment): since the voxel space is
  156. recursively divisible down to a cube of 1 unit on a side, at what point do
  157. you stop and say "this is the cube the object or feature exists in". This is
  158. related to your mention of resolution, but I'm confused as to how to apply
  159. it.  
  160.                                                         --Mark
  161. ...........................................................................
  162.  
  163. Fm: Hans Peter Rushworth 100031,473
  164. To: Mark Betz/Ass't SysOp 76605,2346 (X)
  165.  
  166. >> I'm thinking that, since the node represents a cube, you have to define
  167. the cube's extent.
  168.  
  169. I don't think so Mark. Imagine your 3D space was 1Km x 1Km x 1Km. The root
  170. node of the octree is a cube of those dimensions. If you subdivide this node,
  171. a child of this node is a cube 500m x 500m x 500m (ie one eigth the volume).
  172. The extent of the cube is always known by reference to its depth in the
  173. hierarchy. When "expanding" the octree, you stop when the cube dimensions
  174. would be "the same size as a pixel". If you don't subdivide this way, you
  175. have to do extra checks to make sure you don't have overlapping and
  176. inconsistent spaces. There is no limit to the amount you can subdivide the 3D
  177. space - it is fractal. 
  178.  
  179. >> what to store in the node.
  180.  
  181. You might store a mean value (lets say colour, or material) of whatever is
  182. stored in children of the node. You can use this value when you decide not to
  183. proceed further in processing the tree.
  184.  
  185. >> The most puzzling question (at this moment): since the voxel space is
  186. recursively divisible down to a cube of 1 unit on a side, at what point do
  187. you stop and say "this is the cube the object or feature exists in". This is
  188. related to your mention of resolution, but I'm confused as to how to apply
  189. it.  
  190.  
  191. Say your 3D space represents oil trapped beneath the surface of the earth.
  192. The resolution limit might be determined by how big a drill bit you have, or
  193. how large an volume of oil is worth drilling a hole for.
  194.  
  195. It all depends on what you want to use the octree for.
  196.  
  197. Peter.
  198. ...........................................................................
  199.  
  200. Fm: Mark Betz/Ass't SysOp 76605,2346
  201. To: Hans Peter Rushworth 100031,473 (X)
  202.  
  203. I think I see, Peter. The extent of the cube is determined by the division of
  204. the parent cube. The actual location of the child space inside the parent
  205. cube is determined by it's position, i.e. top-left, middle-center, etc.
  206.  
  207. I assume that the reason you put "pixel" in quotes is that the size of the
  208. pixel is not always one screen pixel. You might have a rectangular solid that
  209. is ten screen pixels on a side, and so you don't deal with it in any finer
  210. resolution.
  211.  
  212. Am I getting close? There is a good discussion of Voxels in Foley, Van Dam,
  213. et al. I'll have to have a look at it tomorrow.
  214.  
  215.                                                         --Mark
  216. ...........................................................................
  217.  
  218. Fm: Hans Peter Rushworth 100031,473
  219. To: Mark Betz/Ass't SysOp 76605,2346 (X)
  220.  
  221. >> Am I getting close?
  222.  
  223. Yes. It doesn't really matter about what you use it for, and therefore what
  224. represents what. The important thing is to realise that the organisation or
  225. "shape" of the tree actually tells you something about the space.
  226.  
  227. Another interesting aspect is that you can directly get the co-ordinates of
  228. a particular voxel by knowing what route you took to get to it. Each node has
  229. upto 8 subtrees. If you number these links 0 to 7, and organise the links so
  230. that the *bits* in the *link number* indicate the 1-bit "co-ordinates" of the
  231. children in XYZ relative to this node where the X Y & Z bits are bits 0,1 and 2
  232. respectively <thats tricky to explain!>, and as you descend the tree with a
  233. max depth "n" you store the bit number in a list, the co-ordinates (xyz) of
  234. current node is:
  235.  
  236.    x = 0; y = 0; z = 0;
  237.    for(int i=0;i<depth;i++)
  238.    {
  239.       int bit = 1<<(n-i);
  240.       if(list[i] & 1) x += bit;
  241.       if(list[i] & 2) y += bit;
  242.       if(list[i] & 4) z += bit;
  243.    }
  244.  
  245. Working the other way, it is easy to see a way of finding the nearest node
  246. to a point in the space given the X,Y and Z co-ordinates.
  247.  
  248. Again, assuming "n" is the max depth of the tree:
  249.  
  250. typedef struct vox_node {
  251.    struct vox_node *link[8]; // pointers to children
  252.    VOX_DATA data;            // whatever...
  253. } VOX_NODE;
  254.  
  255.   VOX_NODE *current = root,*tmp;
  256.       // unsigned so "n" can be upto 16 ;)
  257.   for(unsigned mask = (1<<(n-1)) ; mask ; mask >>= 1)
  258.   {
  259.       probe = current->link[ ((x & mask) ? 1 : 0) +
  260.                              ((y & mask) ? 2 : 0) +
  261.                              ((z & mask) ? 4 : 0) ];
  262.      if(!probe) break;
  263.      current = probe;
  264.   }
  265.   // Now "current" points at nearest voxel
  266.  
  267. (sorry about all the shifts, this would be much easier in assembler <g>).
  268. ...........................................................................
  269.  
  270. Fm: Bob Provencher/GD SL 71621,2632
  271. To: Hans Peter Rushworth 100031,473 (X)
  272.  
  273. Hi Peter,
  274.  
  275. There was an article a few months ago in C Users Journal that concerned
  276. quad-trees and quad-codes.  With a quad-code is was possible to represent
  277. any two-dimensional region.  I suppose your oct-tree is the same idea, and
  278. if you take it further you could encode an oct-code representing any
  279. 3-dimensional object.  Have you seen the article I'm talking about?
  280.  
  281. Bob
  282.  
  283. __________________________ Subj: RGB to Oct Tree ___________________________
  284.  
  285. Fm: Bob Provencher/GD SL 71621,2632
  286. To: Mark Betz/Ass't SysOp 76605,2346 (X)
  287.  
  288. Hi Mark!
  289.  
  290. I was thinking about the RGB to octal-code problem, and I discovered the
  291. answer, it turned out to be deceptively simple!  I'll follow through my
  292. thinking to see if you agree with my conclusions.
  293.  
  294. If you set up your octants so that they correspond to increases in the R, G,
  295. and B directions such that an increase in the R (or x) direction adds 2^0 to
  296. the octant number, an increase in the G adds 2^1, and B adds 2^2 then you
  297. come up with an octant map that looks something like this:
  298.  
  299.     111                 7
  300. 101     110         5       6
  301.     100                 4
  302.  
  303.     011                 3
  304. 001     010         1       2
  305.     000                 0
  306.  
  307. So compute the octant of an rgb value, you simply decide whether it is the
  308. second half of the line which describes the componant you're looking for.
  309.  
  310. So, for example, assuming a cube 63 on a side, the first octant for the rgb
  311. value 32,32,32 is 1,1,1 or 7.  However, 31, 31, 31 is in octant 0,0,0.
  312.  
  313. Now what is really interesting, is that if you examine the values you get,
  314. it turns out the computing the octant is a very straightforward.  At each
  315. step, to see if a value lays within the first or second half of the desired
  316. line, you need only examine the current high bit.
  317.  
  318. What this means is that you can compute the oct-code down to the desired
  319. 6 octants by simply rotating the bit field that represents the RGB value!
  320.  
  321. For example:
  322.  
  323. RGB  63, 31, 0       RGB 0, 0, 0         RGB 63, 0, 63 (Purple)
  324.  
  325. B - 000000  2^2      B - 000000          B - 111111
  326. G - 011111  2^1      G - 000000          G - 000000
  327. R - 111111  2^0      R - 000000          R - 111111
  328.     ------               ------              ------
  329.  Oct 133333               000000              555555
  330.  
  331. So, it's very easy to compute the oct-code, and as we discussed to find RGB
  332. values in the same region as the desired one, you only need examine those
  333. with the same leading 5 digits.  This will give you the seven values to the
  334. right and up from the desired one.  If you were to examine the oct-codes
  335. that had the same 4 leading digits, you would then get values, that could be
  336. to the left of the desired one.
  337.  
  338. If you use the leading 4 digits, worst case would be 64 matches (highly
  339. unlikely in a 256 color pallette).  At that point you'd need to do your
  340. 3-d distance computation, but, if you think about it, you only need to
  341. examine the lowest two bits!  The max distance here would only be 4, so the
  342. max square root you'd need to compute would be 32!  These could easily be
  343. stored in a small lookup table.
  344.  
  345. What do you think?
  346.  
  347. Bob
  348. ...........................................................................
  349.  
  350. Fm: Dan Corritore/MOTM 70243,1110
  351. To: Hans Peter Rushworth 100031,473 (X)
  352.  
  353. I'm sorry, but I still don't understand exactly how this tree structure
  354. works, and, from what Mark said, it sounded like it wastes as much (actually,
  355. more) space as an array, since you have the tree divided up into sections,
  356. and each section either has a null pointer or a linked list.. an array would
  357. have the same stuff, in less space, and less accessing time would be
  358. required.. I guess I need a better description of the voxel tree structure..
  359. Thanks,         _Dan 
  360. ...........................................................................
  361.  
  362. Fm: Dan Corritore/MOTM 70243,1110
  363. To: Mark Betz/Ass't SysOp 76605,2346 (X)
  364.  
  365. Aaaaahhhhhh!!! Are we going around in circles, or what?!?<g> You said that
  366. the tree would be divided into sections, each with either a null pointer, or
  367. a linked list coming off of it, yes? That's exactly what the array would
  368. be... an array of linked lists.. if Null, there's no list, so go to your next
  369. location.. same with the tree, except it's more complicated, and takes more
  370. time..  From what I've heard from you, it sounds to me that you are wasting
  371. space both ways..   Thanks,
  372.         _Dam  
  373. ...........................................................................
  374.  
  375. Fm: Mark Betz/Ass't SysOp 76605,2346
  376. To: Bob Provencher/GD SL 71621,2632 (X)
  377.  
  378. I think I'm beginning to see, Bob, but you lost me on:
  379.  
  380. >> So compute the octant of an rgb value, you simply decide whether it is the
  381. >> second half of the line which describes the componant you're looking for.
  382.  
  383. >> So, for example, assuming a cube 63 on a side, the first octant for the
  384. rgb >> value 32,32,32 is 1,1,1 or 7.  However, 31, 31, 31 is in octant 0,0,0.
  385.  
  386. and also I'm having trouble with the part about "rotating the bitfield that
  387. represents the RGB value". It appears that you're letting each set bit
  388. represent either 0, 2, or 4, and then adding them vertically. I don't get the
  389. part about rotation. Must be missing something basic.
  390.  
  391. This is exciting. I definitely think you might be on to something. Is there a
  392. possibility of a "collision" in this method? In other words, can two
  393. different triplets produce the same octcode?
  394.                                                         --Mark
  395. ...........................................................................
  396.  
  397. Fm: Bob Provencher/GD SL 71621,2632
  398. To: Mark Betz/Ass't SysOp 76605,2346 (X)
  399.  
  400. Hi Mark -
  401.  
  402. >> So compute the octant of an rgb value, you simply decide whether it is the
  403. >> second half of the line which describes the componant you're looking for
  404.  
  405. For R,G and B lines of length 64 (0 through 63) if the value is 31, or less
  406. that bit gets a zero, otherwise it gets a one.  Your just figuring out which
  407. half of the line the value lies in.
  408.  
  409. >> So, for example, assuming a cube 63 on a side, the first octant for the
  410. rgb >> value 32,32,32 is 1,1,1 or 7.  However, 31, 31, 31 is in octant 0,0,0.
  411.  
  412. If the total cube is the cube of sides with length 64, then a
  413. "first-octant" is a subcube of the total cube.  32,32,32 lies in octant 7,
  414. or binary 111 while 31,31,31 lies in octant 0, or binary 000.
  415.  
  416. >> I'm having trouble with the part about "rotating the bitfield that
  417. >> represents the RGB valueif the RGB value is 64,64,64
  418.  
  419. R = 111111 = 64
  420. G = 111111 = 64
  421. B = 111111 = 64
  422.  
  423. Then to get the oct-code you just rotate the bitmap 90 degrees to the right
  424.  
  425. BGR
  426. 111 = 7
  427. 111 = 7
  428. 111 = 7
  429. 111 = 7
  430. 111 = 7
  431. 111 = 7
  432.  
  433. to get your oct-code.
  434.  
  435. I've been thinking about it further.  All we're really doing here is
  436. allowing you to do a comparison on the R, G and B values, and give
  437. them equal weight.  By rotating, we're saying that we want to find values in
  438. the closest cube, not the closest color.  You can define exactly how large
  439. your "closest cube" is by how many low oct-codes you ignore in an octcode.
  440.  
  441. I still think there is a problem with boundary values, but I have another
  442. idea I'll tell you about tomorrow after I work it out.  The problem is
  443. basically that if you're looking for the closest match to 32,32,32, and 31,
  444. 31, 31 exists in the pallette, this method wouldn't necesarily _ever_ find it
  445. as the closest, because it's sort of an equal to or greater than comparison.
  446.  
  447. What we can do is also find the oct-codes for the seven combinations of RGB
  448. values that are one less the the RGB values we're looking for, this will
  449. give us those cubes that are to the left of the one we want.
  450.  
  451. For example for 32, 32, 32 we should really compute a quad code for
  452.  
  453. (32,32,32) - (0, 0, 0) = ( itself   ) = quadcode 700000
  454. (32,32,32) - (0, 0, 1) = (32, 32, 31) = quadcode 344444
  455.            -  0  1  0  =  32, 31, 32  =          522222
  456.            -  0  1  1  =  32, 31, 31  =          166666
  457.            -  1  0  0  =  31, 32, 32  =          611111
  458.            -  1  0  1  =  31, 32, 31  =          255555
  459.            -  1  1  0  =  31, 31, 32  =          433333
  460.            -  1  1  1  =  31, 31, 31  =          077777
  461.  
  462. The problem is, even when you drop out the last octit(?) none of the ranges
  463. fallout (become the same), but I think this is worst case.  If you take a
  464. regular number at random you might find that some of the resulting codes are
  465. the same after dropping the last octal digit.
  466.  
  467. This still adds up to the worst case 64 compares since now we're only
  468. ignoring the last digit, not the last two, and comparing cubes to the left
  469. as well as right.
  470.  
  471. I also see a problem with this if the closest match was greater than 2
  472. away, then you'd have to ignore the last two octal digits and search for
  473. matches.  No, maybe that would still be ok?
  474.  
  475. I'll play with it some more.
  476.  
  477. Bob
  478. ...........................................................................
  479.  
  480. Fm: Mark Betz/Ass't SysOp 76605,2346
  481. To: Bob Provencher/GD SL 71621,2632 (X)
  482.  
  483. Oh, I see! That bit about the rotation was just too simple a concept for me
  484. to grasp immediately <g>.
  485.  
  486. So producing the octcode is very straightforward, but I still don't
  487. understand exactly what you're doing to the extent I'd need to to appreciate
  488. the comments on boundary values. I need to look at it some more, but right
  489. now I'm busy writing a set of small programs for the article. Tell you what,
  490. if you can make it work for a palette lookup, I'll work it into the article
  491. as an alternative technique, for which you will get full credit. Speaking of
  492. which, I have to send you the tree code. Basically the test programs have to
  493. be able to call two functions:
  494.  
  495.  void rgb_sort( char* dactable );
  496.  int rgb_match( char r, char g, char b, int t );
  497.  
  498. The first simply does any initialization work. In my case it builds the tree,
  499. and in yours it would calculate the octcodes and build the array. The second
  500. finds and returns the palette index containing the closest match to the
  501. passed color triplet. The 't' parameter is a threshold value that is specific
  502. to my type of search algorithm. It's basically the vector range on each axis
  503. that we spoke of the other night. You can ignore it.
  504.  
  505. I'l send the tree package along now, so that you have the latest copy of the
  506. source code. It's very small, and hopefully very clear.
  507.  
  508.                                                         --Mark
  509. ...........................................................................
  510.  
  511. Fm: Bob Provencher/GD SL 71621,2632            # 284350 
  512. To: Hans Peter Rushworth 100031,473 (X)        Date: 23-Jan-93  17:16:43
  513.  
  514. Hi Peter -
  515.  
  516. I've just finished reading OCT.DOC.  I think there is some promise to the
  517. method, based on the fact that the 64^3 grid is so sparsely populated, that
  518. I wouldn't need to build the index match down to the sixth level in all
  519. cases.
  520.  
  521. I can check for an entire cube having an exact index match by computing the
  522. eight corners first, then if they are not equal, computing all the values.
  523.  
  524. I can readily adapt the idea of octcodes to your method, which means I won't
  525. necessarily have the overhead of a tree, or I can implement it as a tree.
  526.  
  527. As you point out it may take quite a bit of memory, and I'm also wondering
  528. if building the index values for the 64^3 space (given that we won't have to
  529. compute all of these) will still take too long.
  530.  
  531. It does sound promising, though, I'm going to try it out, thanks!
  532.  
  533. One thing though, isn't the formula for computing the distance between to
  534. three dimensional co-ordinates the square-root of the some of the squares of
  535. the x, y and z differences, or sqr( (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 )?
  536. ...........................................................................
  537.  
  538. Fm: Hans Peter Rushworth 100031,473            # 284412 
  539. To: Bob Provencher/GD SL 71621,2632 (X)        Date: 23-Jan-93  19:27:22
  540.  
  541. >> [distance =] sqr( (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 )?
  542.  
  543. That is right, my brain must have flipped.
  544.  
  545. >> I can check for an entire cube having an exact index match by computing
  546. the eight corners first, then if they are not equal, computing all the values.
  547.  
  548. No Bob, If they are not equal, you have to bisect the cube into 8 more cubes
  549. and repeat the test for each new cube recursively. You stop doing this when
  550. all the corners are equal. The only time you actualy check all the points is
  551. when the cube you have is 2x2x2, (obviously because in that case the 8 points
  552. are all the points). Otherwise checking all the points would take a very long
  553. time. 
  554.  
  555. >> based on the fact that the 64^3 grid is so sparsely populated.
  556.  
  557. Well, it is fully populated (every colour has an index), the storage method
  558. just identifies where the value changes from one to another, it is
  559. effectively storing the boundaries of each clump of the same index in a way
  560. that is easy to search.
  561.  
  562. >> I can readily adapt the idea of octcodes to your method, which means I
  563. won't necessarily have the overhead of a tree, or I can implement it as a
  564. tree. 
  565.  
  566. I would do it as a tree first, just to make sure the scheme is correct.
  567. ...........................................................................
  568.  
  569. Fm: Bob Provencher/GD SL 71621,2632            # 284511 
  570. To: Hans Peter Rushworth 100031,473 (X)        Date: 23-Jan-93  22:22:08
  571.  
  572. >> No Bob, If they are not equal, you have to bisect the cube into 8 more
  573. >> cubes and repeat the test for each new cube recursively. You stop doing
  574. >> this when all
  575.  
  576. Right, I understood this but sort of typed something completely different
  577. <g>.
  578.  
  579. >> Well, it is fully populated (every colour has an index), the storage
  580. >> method just identifies where the value changes from one to another, it is
  581. >> effectively storing the boundaries of each clump of the same index in a
  582. >> way that is easy to search.
  583.  
  584. Right, but there will only be 256 different indexes in the tree.  In some
  585. cases we may only have to search the tree to three levels (or match the
  586. octcodes by the left three).  Worst case would of course be 6 levels, but
  587. that shouldn't happen unless we have some adjacant or very close colors,
  588. right?
  589.  
  590. >> I would do it as a tree first, just to make sure the scheme is correct.
  591.  
  592. You're right, it's easier to do it recursively first and worry about
  593. implementation details later.
  594. ...........................................................................
  595.  
  596. Fm: Hans Peter Rushworth 100031,473            # 284548 
  597. To: Bob Provencher/GD SL 71621,2632 (X)        Date: 23-Jan-93  23:46:33
  598.  
  599. >> Right, but there will only be 256 different indexes in the tree.  In some
  600. cases we may only have to search the tree to three levels (or match the
  601. octcodes by the left three).  Worst case would of course be 6 levels, but
  602. that shouldn't happen unless we have some adjacant or very close colors,
  603. right? 
  604.  
  605. Right. It all depends on where the edges happen to be, you can get lucky.
  606.  
  607. BTW I have no justification for the "corner" algorithm. I thought of that
  608. while I was writing that file. I've a Gut feeling it is correct, I suppose it
  609. is rather like the 4-colour (or was it 3-colour) map problem. If it fails
  610. then there is probably a faster way of searching for the nearest index. The
  611. way this would work is that you only search indexes that are
  612.  
  613. (1) inside the cube being tested
  614.  
  615. (2) already lying along the edges of the cube (IOW test all points along each
  616. of the edges of the cube). 
  617.  
  618. Initially the search set is the entire 256 colour index set. At each level of
  619. recursion, you reduce this by eliminating the cases that don't suceed the two
  620. above tests. Typically this might reduce your colour index set from 256 to
  621. 256/8, which is a substantial saving. In fact it might be a good idea to use
  622. this method in place of the 8-point test.
  623.  
  624. To expand on these tests, consider the following (contrived) quadtree
  625. sub-node case:
  626.  
  627.    1 1 1 1 2 2 2 2
  628.    1 * * * * * * 2
  629.    1 * *(5)* * * 2
  630.    1 * * * * * * 2
  631.    4 * * *(6)* * 3
  632.    4 * * * * * * 3
  633.    4 * * * * * * 3
  634.    4 4 4 3 3 3 3 3
  635.  
  636. You would search all the edge points finding the nearest index. In this case
  637. you find indices 1-4. The indices 5 & 6 lie inside the quad. You can now
  638. eliminate all the other indexes for subsequent recursive tests for the
  639. points marked * and this will be much quicker than checking all 256 of the
  640. indices. You should also be able to eliminate all internal indices (5 & 6)
  641. that don't ALSO appear on an edge from ALL other tests.
  642.  
  643. This should speed the initial setup (tree)mendously.
  644.  
  645. Peter.
  646. ...........................................................................
  647.  
  648. Fm: Bob Provencher/GD SL 71621,2632            # 284803 
  649. To: Hans Peter Rushworth 100031,473 (X)        Date: 24-Jan-93  12:12:33
  650.  
  651. >> BTW I have no justification for the "corner" algorithm.
  652.  
  653. Yeah, it seems like it has to be right.  I couldn't prove it formally, but I
  654. think it must ok.
  655.  
  656. >> (1) inside the cube being tested
  657. >> (2) already lying along the edges of the cube (IOW test all points along
  658. >> each of the edges of the cube).
  659. >> Initially the search set is the entire 256 colour index set. A each
  660. >> level of...
  661.  
  662. I think this sort of what I was trying to do before.  It failed whenever the
  663. actual closest index fell just outside the cube.  It might have to be
  664. extended to one-half the width of the cube.
  665. ...........................................................................
  666.  
  667. Fm: Mark Betz/Ass't SysOp 76605,2346           # 285922 
  668. To: Hans Peter Rushworth 100031,473 (X)        Date: 26-Jan-93  00:07:09
  669.  
  670. I did send it to Bob. I think it was the source of his misery and lack of
  671. time spent with his fiance <g>.
  672.  
  673. My implementation uses a binary space partitioning tree to partition the RGB
  674. cube at each node. The compare key rotates with each level in the tree, such
  675. that red is compared at level 0, green at level 1, blue at level 2, and so
  676. on. The tree requires 2304 bytes for a 256-color palette, and another 1500
  677. bytes or so for the code to build and search the tree. On my 486 it will
  678. produce an accurate match in about .9 ms, depending on the depth of the
  679. search path. I'm sure it could be made faster, since the nature of palette
  680. data produces a pretty terrible looking binary tree. I'm using a staggered
  681. insertion order when building the tree to avoid hitting any gradient ranges,
  682. but I still get a very deep tree for some palettes. I'd like to know if
  683. there's a way to balance a BSP tree. I suspect there isn't, since the
  684. relative position of nodes in the tree is part of the information contained.
  685. Have any ideas on this? 
  686.  
  687. Btw, what's your schedule this weekend? I'd like to give you a call, and need
  688. a good time. Could you PRI your number to me in case I can't find it?
  689.  
  690.                                                         --Mark
  691. ...........................................................................
  692.  
  693. Fm: Hans Peter Rushworth 100031,473            # 286098 
  694. To: Mark Betz/Ass't SysOp 76605,2346 (X)       Date: 26-Jan-93  11:20:56
  695.  
  696. >> I'd like to know if there's a way to balance a BSP tree.
  697.  
  698. I don't know if this helps in thinking about it, but three levels of BSP tree
  699. can be equivalent to a single octree node.
  700.  
  701. In that case I would imagine the max depth of your tree is 18 (6x3), and that
  702. sounds reasonable to me. I'm quite amazed that your tree uses only 2304
  703. bytes, which is much less than I would have guessed, but I suppose that can
  704. change depending on the colours that are actually in the palette.
  705.  
  706. >> the relative position of nodes in the tree is part of the information
  707. contained.
  708.  
  709. One way to find out is to alter the ordering scheme (instead of R, G then B)
  710. try B, G then R. To balance the tree try to pick the partition (R G or B)
  711. that splits the tree with even "weight" on either side at any given level.
  712. This heuristic won't always give the optimum balance, but is perhaps a good
  713. place to start. Usually you will want to ensure that for three levels of the
  714. tree you have selected an R G & B transition at least once. But Imagine also
  715. a palette that has only Red and Green and no blue colours.
  716. ...........................................................................
  717.  
  718. Fm: Mark Betz/Ass't SysOp 76605,2346           # 286162 
  719. To: Hans Peter Rushworth 100031,473            Date: 26-Jan-93  13:59:07
  720.  
  721. Hi, Peter. Interesting. Btw, the size of the tree doesn't change depending on
  722. the colors in the palette. I don't look for duplicates: each triplet gets a
  723. node. Each node consists of a triplet, two child pointers, and the index of
  724. the original palette entry on which the node is based. Since the tree is
  725. actually built in an array, the child pointers are 2-byte indices, and not 4
  726. byte pointers, saving 2 words per node.
  727.  
  728. I think your estimate of the max depth is pretty close. Part of the
  729. constraint of searching this kind of tree, is that you have to search both
  730. subtrees anytime the current node falls within a "window" on either side of
  731. the compare key. So for certain colors I end up searching 30-40 nodes. A lot
  732. better than searching the whole palette, but there must be room for
  733. improvement. 
  734.                                                         --Mark
  735.  
  736. ________________________ Subj: VGA Transparency code ________________________
  737.  
  738. Fm: VOR Technologies Inc 71333,134             # 312076 
  739. To: ALL                                        Date: 11-Mar-93  10:23:25
  740.  
  741. All,
  742.  
  743. Does anyone know of some existing code or have a good algorthym for doing
  744. blends/mixes/transparencies etc with the VGA Palette. There are a couple of
  745. things though, given that i am using a static 256 color palette (256 colors
  746. were chosen and cant be changed for this program). Does anyone know of an
  747. algorythm for selecting a value for a color that shows through another color
  748. (i.E. i have a red rectanlg
  749.  
  750. i place a blue one on top that i deem to be 50% trasnparent i should then be
  751. able to choose something in the purple area). I know various graphics program
  752. do it, but am not sure of an algorythm or existing code that might be
  753. available.
  754.  
  755. Thanks,
  756.  
  757. Chris Eisnaugle Vor Technologies Inc.
  758. ...........................................................................
  759.  
  760. Fm: Jaimi McEntire 71700,1202                  # 312143 
  761. To: VOR Technologies Inc 71333,134 (X)         Date: 11-Mar-93  12:49:40
  762.  
  763. Chris,
  764.  
  765.    You could do it the "Cheesy" way... ie:    Multiply the transparent color
  766. register (R,G,and B seperately) byt the transparency amount, multiply the
  767. color which you're plotting on by the remainder, add the R from source and
  768. dest, G from source and dst, and B from source and dest. then divide the
  769. results by 100, and that should give you the optimum RGB. Then just search
  770. through your palette to find the closest match.
  771.  
  772.     pixel = GetPixel(x,y)
  773.     pixel.red *= transparency_perc;
  774.     pixel.green *= transparency_perc;
  775.     pixel.blue  *= transparency_perc;
  776.     destpixel = GetPixel(destx,desty);
  777.     destpixel.red *= (100-transparency_perc);
  778.     destpixel.green *= (100-transparency_perc);
  779.     destpixel.blue  *= (100-transparency_perc);
  780.     optimum.red = (pixel.red + destpixel.red)/100;
  781.     optimum.green = (pixel.green + destpixel.green)/100;
  782.     optimum.blue  = (pixel.blue + destpixel.blue)/100;
  783.     // now find optimum color in palette.
  784.     // and set dest pixel to closest to optimum
  785.  
  786. Good luck!
  787.  
  788. P.S. this wont compile obviously. It's just an algorithm and a slow one.
  789.      you could get much better performance if you used shifts, instead of
  790.      divides, but then you would need to limit the transparency levels.
  791.  
  792. Jaimi McEntire
  793. ...........................................................................
  794.  
  795. Fm: Mark Betz/Ass't SysOp 76605,2346           # 312351 
  796. To: VOR Technologies Inc 71333,134 (X)         Date: 11-Mar-93  20:36:07
  797.  
  798. Hi, Chris. If you want to put Jaimi's method to work, I have some code which
  799. will select the best match for a given RGB from a palette. It builds a binary
  800. search tree of color values, and takes about .10 ms to do a lookup on my
  801. 486-33. The code and data is about 5K.
  802.                                                         --Mark
  803. ...........................................................................
  804.  
  805. Fm: Mark Betz/Ass't SysOp 76605,2346           # 312780 
  806. To: VOR Technologies Inc 71333,134 (X)         Date: 12-Mar-93  21:26:44
  807.  
  808. I'll send it along tonight, Chris. The code is public domain, but I'd
  809. appreciate it if you didn't distribute it until after July, since it is part
  810. of an article that I have submitted to a magazine.
  811.  
  812.  
  813.                                                         --Mark
  814.  
  815. ___________________________ Subj: Mark's article ___________________________
  816.  
  817. Fm: Patrick Reilly 71333,2764                  # 376998 
  818. To: Mark Betz/Ass't SysOp 76605,2346 (X)       Date: 15-Jun-93  19:49:12
  819.  
  820. Mark,
  821.   Thanks - I look forward to reading it (haven't gotten the last DDJ yet)...
  822.   I was thinking about bitmap transforms; do you know if its possible,
  823. probable, desirable, or already done <g> to take a square bitmap whose
  824. elements are made up of a RGB triple and have a transform matrix that, if you
  825. multiply your bitmap times it, will shade it for distance and do a "nice"
  826. rotation/translation of it? IOW if you start out with, say, a 4x4 matrix
  827. that's a bitmap that represents a (tiny) wall in RGB triplets when viewed
  828. head-on at a distance of 0 - can a single matrix of RGBs be created that will
  829. translate, rotate, and shade for distance the bitmap (with a specific RGB
  830. quantity - say, <0,0,0> set to be 'transparent') so that if you now displayed
  831. the bitmap, it would look like a 3D rendered texture of a wall that's 3 units
  832. away and rotated about the vertical axis 60 degrees (with depth shading)?
  833.   I was going to start playing with the idea (this would allow having all the
  834. bitmaps for the walls, floors and ceilings loaded into memory, a list of
  835. about 40 or so of these transform matrices, and drawing a 'world' would only
  836. require doing the matrix multiply for each panel with the appropriate
  837. transform, do another transform for the new bitmap's starting <x,y> location
  838. on the screen, and displaying) but if this is 'old hat' <g> or has been tried
  839. and found lacking, or is plain impossible, then I won't waste my time.
  840.   I read Abrash's articles for X-Sharp, but for something like a fixed view
  841. of panels which, in real-world coords, form a lattice, it seems that's not a
  842. very good approach...
  843.      -Pat-
  844. ...........................................................................
  845.  
  846. Fm: Patrick Reilly 71333,2764                  # 377238 
  847. To: Mark Betz/Ass't SysOp 76605,2346 (X)       Date: 16-Jun-93  00:17:25
  848.  
  849. Mark,
  850.   I figured to use a lookup table to map the RGB triplet to a palette entry;
  851. this would eliminate the problem of having to have the palette laid out so
  852. that, for example, dark colors are near 0, light colors near 255, etc, but
  853. would still allow having a triplet so that the transform matrix would make
  854. 'sense'. Also, multiplying the bitmap by a scalar would make sense too: IE
  855. using a scalar of <0.75,0.75,0.75> would darken the whole bitmap evenly to
  856. 3/4 intensity. With a lookup table, I would think the conversion (from 1-byte
  857. element matrix to RGB element matrix) would be quick enough. Of course, each
  858. conversion would require a filter to 'round' the RGB value to the 'nearest'
  859. mapping element. 
  860.   So you haven't heard of anyone trying this? I'll have to play a bit <g>;
  861. what I would like to end up with is: 1) convert the NxN bitmap to an NxN RGB
  862. matrix; 2) multiply the matrix by the appropriate transform matrix (IE if
  863. this panel is the 'floor' at cell <-3,+4> from current POV, use
  864. transformMatrix[18]); 3) use a filter on the transformed matrix so that the
  865. RGB elements can map to palette entries; 4) convert the matrix back into a
  866. bitmap; 5) look up the <x,y> pair for a floor at <-3,+4> from the POV and
  867. paint the bitmap at <x,y>. If it *can* be done (ie one matrix will do the
  868. complete conversion), then a nice, slow, floating-point program can generate
  869. all the transforms and lookup tables for the <x,y> coords. Once these are
  870. calculated, they can just be hardcoded into the program.
  871.   I'll let you know if I can come up with anything.
  872.        -Pat-
  873. ...........................................................................
  874.  
  875. Fm: Patrick Reilly 71333,2764                  # 377289 
  876. To: Mark Betz/Ass't SysOp 76605,2346 (X)       Date: 16-Jun-93  04:27:26
  877.  
  878. Mark,
  879.   Oh well... its a no-show on a simple transform. A simple example shows why:
  880. consider having a 4x4 bitmap (elements A(ij)), and wanting it to be
  881. transformed onto the 'floor' panel immediately in front of the view plane;
  882. what I'd want when the transform is complete would be for A(41) to have the
  883. colors 0.65*(0.5*A(41) + 0.5*A(31)). To get such a product, the bitmap would
  884. have to multiply on the right the transform matrix; but A(32) wants to be
  885. 0.03*A(31) + 0.5*A(32) + ..., which means that the bitmap has to multiply on
  886. the *left* the transform matrix...
  887.  
  888.   I'll play some more; maybe its possible to use 2 matrices; one that
  889. multiplies on the left and transforms/alias' vertical pixels, and one that
  890. multiplies on the right and transforms/alias' horizontal pixels, then sum the
  891. two resultant RGB bitmaps... The bummer is that now I'd have to store *twice*
  892. as many matrices...
  893. ...........................................................................
  894.  
  895.  
  896.